package com.yunhe.abnormal.service.data.impl;

import com.yunhe.abnormal.client.AuthorityClient;
import com.yunhe.abnormal.consts.AlarmConsts;
import com.yunhe.abnormal.domain.data.AbnormalSmsConfig;
import com.yunhe.common.exception.ArgumentErrorException;
import com.yunhe.common.exception.ObjectNotFoundException;
import com.yunhe.common.exception.UniqueConstraintsException;
import com.yunhe.common.exception.UserNotFoundException;
import com.yunhe.common.model.PageParam;
import com.yunhe.common.model.authority.Role;
import com.yunhe.common.model.authority.UserDTO;
import com.yunhe.abnormal.repository.data.AbnormalSmsConfigRepository;
import com.yunhe.abnormal.service.data.AbnormalSmsConfigService;
import com.yunhe.common.util.HeaderUtil;
import com.yunhe.common.util.QueryUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.persistence.criteria.Predicate;
import java.sql.Time;
import java.time.LocalTime;
import java.util.*;

@Service
public class AbnormalSmsConfigServiceImpl implements AbnormalSmsConfigService {

    @Autowired
    private AbnormalSmsConfigRepository abnormalSmsConfigRepository;
    @Autowired
    private AuthorityClient authorityClient;
    @Autowired
    private HeaderUtil headerUtil;

    private Map<String, String> alarmLevelTitleMap = new HashMap<>(4);

    @PostConstruct
    private void init() {
        alarmLevelTitleMap.put(AlarmConsts.ALARMLEVEL.IGNORE.getName(), AlarmConsts.ALARMLEVEL.IGNORE.getTitle());
        alarmLevelTitleMap.put(AlarmConsts.ALARMLEVEL.SLIGHT.getName(), AlarmConsts.ALARMLEVEL.SLIGHT.getTitle());
        alarmLevelTitleMap.put(AlarmConsts.ALARMLEVEL.MODERATE.getName(), AlarmConsts.ALARMLEVEL.MODERATE.getTitle());
        alarmLevelTitleMap.put(AlarmConsts.ALARMLEVEL.SERIOUS.getName(), AlarmConsts.ALARMLEVEL.SERIOUS.getTitle());
    }

    private void processBeforeSave(AbnormalSmsConfig config)
            throws UniqueConstraintsException, ArgumentErrorException, ObjectNotFoundException, UserNotFoundException {
        UserDTO user = authorityClient.getUserById(config.getUserId()).getBody().getResults();
        if (user == null) {
            throw new UserNotFoundException("该用户不存在");
        }
        AbnormalSmsConfig byUserId = this.findByUserId(config.getUserId());
        if (config.getId() == null && byUserId != null) {
            throw new UniqueConstraintsException("已存在相同的配置");
        } else if (byUserId != null && byUserId.getId() != config.getId()) {
            throw new UniqueConstraintsException("已存在相同的配置");
        }
        config.setUserName(user.getName());
        config.setUserTitle(user.getTitle());
        AbnormalSmsConfig byICodeAndPhone = abnormalSmsConfigRepository.findByICodeAndPhone(config.getInternationalCode(), config.getPhone());
        if (config.getId() == null && byICodeAndPhone != null) {
            throw new UniqueConstraintsException("该手机号已被使用");
        }
        if (config.getId() != null && byICodeAndPhone != null && config.getId() != byICodeAndPhone.getId()) {
            throw new UniqueConstraintsException("该手机号已被使用");
        }
    }

    @Override
    public AbnormalSmsConfig createConfig(AbnormalSmsConfig abnormalSmsConfig)
            throws UniqueConstraintsException, ArgumentErrorException, ObjectNotFoundException, UserNotFoundException {
        if (abnormalSmsConfig.getFirmId() == null) {
            Long firmId = headerUtil.getHeaderFirmId();
            abnormalSmsConfig.setFirmId(firmId);
        }
        Long createdUserId = headerUtil.getHeaderUserId();
        abnormalSmsConfig.setCreatedByAdmin(false);
        List<Role> roles = authorityClient.getRolesByUserId(createdUserId).getBody().getResults();
        for (Role r : roles) {
            if (r.getName().contains("Admin")) {
                abnormalSmsConfig.setCreatedByAdmin(true);
            }
        }
        abnormalSmsConfig.setId(null);
        processBeforeSave(abnormalSmsConfig);
        AbnormalSmsConfig result = abnormalSmsConfigRepository.save(abnormalSmsConfig);
        return result;
    }

    @Override
    public void delete(Long id) {
        abnormalSmsConfigRepository.deleteById(id);
    }

    @Override
    public AbnormalSmsConfig updateConfig(AbnormalSmsConfig abnormalSmsConfig) throws UniqueConstraintsException, ArgumentErrorException, ObjectNotFoundException, UserNotFoundException {
        AbnormalSmsConfig byId = abnormalSmsConfigRepository.findById(abnormalSmsConfig.getId()).orElse(null);
        abnormalSmsConfig.setFirmId(byId.getFirmId());
        abnormalSmsConfig.setCreatedByAdmin(byId.getCreatedByAdmin());
        processBeforeSave(abnormalSmsConfig);
        AbnormalSmsConfig result = abnormalSmsConfigRepository.save(abnormalSmsConfig);
        return result;
    }

    @Override
    public AbnormalSmsConfig updateConfig(Long id,
                                          Optional<Long> userId,
                                          Optional<String> internationalCode,
                                          Optional<String> phone,
                                          Optional<String> dtime,
                                          Optional<Boolean> remind)
            throws UniqueConstraintsException, ArgumentErrorException, ObjectNotFoundException, UserNotFoundException {
        AbnormalSmsConfig config = abnormalSmsConfigRepository.findById(id).orElse(null);
        if (config == null) {
            throw new ObjectNotFoundException("配置不存在");
        }
        userId.ifPresent(config::setUserId);
        internationalCode.ifPresent(config::setInternationalCode);
        phone.ifPresent(config::setPhone);
        dtime.ifPresent(config::setDtime);
        remind.ifPresent(config::setRemind);
        processBeforeSave(config);
        AbnormalSmsConfig result = abnormalSmsConfigRepository.save(config);
        return result;
    }

    @Override
    public AbnormalSmsConfig findById(Long id)
            throws ObjectNotFoundException {
        AbnormalSmsConfig result = abnormalSmsConfigRepository.findById(id).orElse(null);
        if (result == null) {
            throw new ObjectNotFoundException("配置不存在");
        }
        return result;
    }

    @Override
    public AbnormalSmsConfig findByUserId(Long id) throws ObjectNotFoundException {
        return abnormalSmsConfigRepository.findByUserId(id);
    }

    @Override
    public AbnormalSmsConfig findByUserIdNeedInformed(Long id) throws ObjectNotFoundException {
        AbnormalSmsConfig result = abnormalSmsConfigRepository.findByUserIdNeedInform(id);
        Boolean compareResult = comareTime(result);
        if (result != null && compareResult) {
            return result;
        } else {
            return null;
        }
    }

    private boolean comareTime(AbnormalSmsConfig abnormalSmsConfig) {
        Boolean result = false;
        if (abnormalSmsConfig == null) {
            return result;
        }
        List<List<LocalTime>> dtimes = getTimeList(abnormalSmsConfig);
        if (dtimes == null) {
            result = false;
        } else {
            LocalTime now = LocalTime.now();
            for (List<LocalTime> localTimes : dtimes) {
                if (localTimes.get(0).isBefore(now) && localTimes.get(1).isAfter(now)) {
                    result = true;
                } else {
                    result = false;
                }
            }
        }
        return result;
    }

    @Override
    public Iterable<AbnormalSmsConfig> search(Long firmId,
                                              Optional<String> phone,
                                              Optional<String> queryStr,
                                              PageParam pageParam) {
        Specification spec = (root, query, cb) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(cb.equal(root.get("firmId"), firmId));
            if (phone.isPresent()) {
                list.add(cb.equal(root.get("phone"), phone.get()));
            }
            if (queryStr.isPresent()) {
                list.add(cb.or(cb.like(root.get("userName"), "%" + queryStr.get().replace("%", "\\%") + "%"),
                        cb.like(root.get("userTitle"), "%" + queryStr.get().replace("%", "\\%") + "%"),
                        cb.like(root.get("phone"), "%" + queryStr.get().replace("%", "\\%") + "%")));
            }
            if (list.size() == 1) {
                query.where(list.get(0));
            } else {
                query.where(list.toArray(new Predicate[0]));
            }
            return null;
        };
        Iterable<AbnormalSmsConfig> results;
        if (QueryUtil.needPaging(pageParam)) {
            List<String> sortList = pageParam.getSort();
            if (sortList == null) {
                List<String> list = new ArrayList<>();
                list.add("-id");
                pageParam.setSort(list);
            }
            Pageable pageable1 = QueryUtil.getPageRequest(pageParam);
            results = abnormalSmsConfigRepository.findAll(spec, pageable1);
            return results;
        } else {
            Sort sort = pageParam == null ? null : QueryUtil.getSort(pageParam.getSort());
            if (sort != null) {
                results = abnormalSmsConfigRepository.findAll(spec, sort);
                return results;
            } else {
                results = abnormalSmsConfigRepository.findAll(spec);
                return results;
            }
        }
    }

    public static List<List<LocalTime>> getTimeList(AbnormalSmsConfig abnormalSmsConfig) {
        String dtime = abnormalSmsConfig.getDtime();
        String[] arr = dtime.split(",");
        List<List<LocalTime>> resultList = new ArrayList<>();
        if (arr.length > 0) {
            for (String str : arr) {
                String[] times = str.split("-");
                if (times != null && times.length == 2) {
                    Time startTime = Time.valueOf(times[0]);
                    Time endTime = Time.valueOf(times[1]);
                    //比较开始时间和结束时间，针对20:00-08:00做处理
                    if (startTime.before(endTime)) {
                        List<LocalTime> result = new ArrayList<>();
                        result.add(startTime.toLocalTime());
                        //减1做特殊处理
                        result.add(endTime.toLocalTime().minusMinutes(1));
                        resultList.add(result);
                    } else {
                        Time zeroTime = Time.valueOf("00:00:00");
                        List<LocalTime> result = new ArrayList<>();
                        result.add(startTime.toLocalTime());
                        result.add(zeroTime.toLocalTime());
                        resultList.add(result);
                        result = new ArrayList<>();
                        result.add(zeroTime.toLocalTime());
                        result.add(endTime.toLocalTime());
                        resultList.add(result);
                    }
                }
            }
        }
        return resultList;
    }
}
